#include "myStdio.h"


FILE_* fopen_(const char* path_name, const char* mode)
{
    int flags = 0;      //模式
    if(strcmp(mode, "r")==0)
    {
        flags |= O_RDONLY;
    }
    else if(strcmp(mode, "w")==0)
    {
        flags |= O_WRONLY | O_CREAT | O_TRUNC;
    }
    else if(strcmp(mode, "a")==0)
    {
        flags |= O_WRONLY | O_CREAT | O_APPEND;
    }

    int fd =0;
    if(flags & O_RDONLY) 
        fd = open(path_name, flags);
    else
        fd = open(path_name, flags, 0666);
   
    //打开文件失败，向stderr打印错误，并返回NULL
    if(fd < 0)
    {
        const char* err = strerror(errno);
        write(2, err, strlen(err));
        return NULL;
    }

    FILE_* fp = (FILE_*)malloc(sizeof(FILE_));
    assert(fp);
    fp->flags = SYNC_LINE;  //默认设置为行刷新
    fp->fileno = fd;
    fp->cap = SIZE;
    fp->size = 0;
    memset(fp->buffer, 0, SIZE);

    return fp;
}
//这个fwrite简化了，系统的太复杂，不好写
//*ptr是要写的内容，num是写几个，fp确定写到哪个文件
void fwrite_(const void* ptr, int num, FILE_* fp)
{
    //1、把数据拷贝到缓冲区
    //有可能缓冲区还有没刷新出去的数据，所以新的数据ptr要从+size位置开始存
    memcpy(fp->buffer + fp->size, ptr, num);    //这里我们不考虑缓冲区溢出的问题
    fp->size += num;

    //2、判断是否刷新缓冲区
    if(fp->flags == SYNC_NOW)
    {
        write(fp->fileno, fp->buffer, fp->size);
        fp->size=0;
    }
    else if(fp->flags == SYNC_LINE)
    {
        //if(*(fp->buffer+fp->size-1)=='\0')  //abc\nabc，暂时不考虑
        if(fp->buffer[fp->size-1]=='\n')  //abc\nabc，暂时不考虑
        {
            write(fp->fileno, fp->buffer, fp->size);
            fp->size=0;
        }
    }
    else if(fp->flags == SYNC_FULL)
    {
        if(fp->size >= fp->cap)
        {
            write(fp->fileno, fp->buffer, fp->size);
            fp->size=0;
        }
    }
}

void fflush_(FILE_* fp)
{
    if(fp->size > 0)
    {
        //c函数fwrite是把数据先拷贝到c提供的缓冲区，然后再调用write，将数据从缓冲区拷贝到内核缓冲区
        //然后可以调用fsync(int fd)，强制将内核缓冲区的数据写入文件
        //如果不调用，什么时候写入全凭OS决定
        write(fp->fileno, fp->buffer, fp->size);
    }
    fsync(fp->fileno);
    fp->size = 0;     
}   

void fclose_(FILE_* fp)
{
    fflush_(fp);
    close(fp->fileno);
}









